#include "manifest.h"

bool strequ(const char* s1, const char* s2) {
    return s1 == null || s2 == null ? s1 == s2 : (s1 == s2 || strcmp(s1, s2) == 0);
}

static pthread_mutex_t alloc_mutex = PTHREAD_MUTEX_INITIALIZER;
static volatile int64 total_allocations;
static volatile int64 total_allocated;

void* mem_allocz(size_t size) {
    void* a = mem_alloc(size + sizeof(size_t));
    if (a != null) {
        memset(a, 0, size);
    }
    return a;
}

void* mem_alloc(size_t size) {
    void* a = malloc(size + sizeof(size_t));
#ifdef DEBUG
    if (a != null) {
        size_t* s = &((size_t*)a)[-1];
        int allocated = (*s + 3) & ~0x3; /* malloc_usable_size(r); */
        pthread_mutex_lock(&alloc_mutex);
        total_allocations++;
        total_allocated += allocated;
        pthread_mutex_unlock(&alloc_mutex);
//      trace("%p allocated=%d size=%d total %lld in %lld chunks", a, allocated, size, total_allocated, total_allocations);
    }
#endif
    return a;
}

void mem_free(void* a) {
    if (a != null) {
#ifdef DEBUG
        size_t* s = &((size_t*)a)[-1];
        size_t allocated = (*s + 3) & ~0x3;
        pthread_mutex_lock(&alloc_mutex);
        total_allocations--;
        total_allocated -= allocated;
        pthread_mutex_unlock(&alloc_mutex);
//      trace("%p allocated=%d total %lld in %lld chunks", a, allocated, total_allocated, total_allocations);
#endif
        free((void*)a);
    }
}

char* mem_strdup(const char* s) {
    assertion(s != null, "invalid parameter s=%p", s);
    return mem_dup(s, strlen(s) + 1);
}

void* mem_dup(const void* a, size_t bytes) {
    assertion(a != null && bytes > 0, "invalid parameters a=%p bytes=%d", a, bytes);
    void* r = null;
    if (a != null && bytes > 0) {
        r = mem_alloc(bytes);
        assert(r != null);
        if (r != null) {
            memcpy(r, a, bytes);
        }
    }
    return r;
}

int64 mem_allocated() {
    return total_allocated;
}

int64 mem_allocations() {
    return total_allocations;
}

